package com.vedu.role.service.impl;

import com.diandian.exception.MyRunTimeException;
import com.diandian.util.BeanCopyUtil;
import com.diandian.util.MyUtil;
import com.vedu.resource.service.ResourceService;
import com.vedu.role.dao.RoleMapper;
import com.vedu.role.dao.UserRoleMapper;
import com.vedu.role.entity.bo.RoleBo;
import com.vedu.role.entity.po.RolePo;
import com.vedu.role.entity.po.UserRolePo;
import com.vedu.role.service.RoleService;
import com.vedu.user.service.UserService;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * version: 1.0
 *
 * @author yuancheng.li [create on 2018/8/15 0:36 ]
 */
@Service
public class RoleServiceImpl implements RoleService {

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private UserRoleMapper userRoleMapper;

    @Autowired
    private UserService userService;

    private ResourceService resourceService;

    @Override
    public List<RoleBo> findByUserId(Integer userId) {

        // check param
        MyUtil.checkNull(userId, "userId");

        List<RoleBo> roleBos = Collections.EMPTY_LIST;
        List<UserRolePo> userRoles = userRoleMapper.findByUserId(userId);
        if (CollectionUtils.isNotEmpty(userRoles)) {
            roleBos = userRoles.stream().map(userRolePo -> {
                RolePo rolePo = roleMapper.findById(userRolePo.getRoleId());
                return BeanCopyUtil.sourceToTarget(rolePo, RoleBo.class);
            }).collect(Collectors.toList());
        }

        return roleBos;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean createRole(Integer userId, RoleBo role) {

        //
        MyUtil.checkNull(userId, "userId");
        MyUtil.checkNull(role, "role");
        // TODO key properties check


        int count = roleMapper.insertSelective(BeanCopyUtil.sourceToTarget(role, RolePo.class));

        return count == 1;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean setUserRoles(Integer userId, Integer targetUserId, Set<Integer> roleIds) {

        MyUtil.checkNull(roleIds, "roleIds");

        // check user is exists
        if (!userService.findUserExists(userId)) {
            throw new MyRunTimeException("", "");
        }
        if (!userService.findUserExists(targetUserId)) {
            throw new MyRunTimeException("", "");
        }
        // check role是否存在
        roleIds.parallelStream().forEach(roleId -> {
            if (roleMapper.findById(roleId) == null) {
                throw new MyRunTimeException("", "");
            }
        });

        List<RoleBo> userRoles = findByUserId(userId);

        //
        List<String> userResources = resourceService.findUserResourceIds(userId);
        Set<String> targetUserSources = new HashSet<>();
        roleIds.stream().forEach(roleId -> {
            List<String> resources = resourceService.findRoleResourceId(roleId);
            if (CollectionUtils.isNotEmpty(resources)) {
                targetUserSources.addAll(resources);
            }
        });
        // check if role more than source user role
        if (!checkContains(userResources, targetUserSources)) {
            throw new MyRunTimeException("", "");
        }

        // 删除关联的role
        userRoleMapper.deleteByUserId(userId);
        // 插入新的role
        roleIds.parallelStream().forEach(roleId -> {
            UserRolePo userRolePo = new UserRolePo(userId, roleId);
            userRoleMapper.insertSelective(userRolePo);
        });

        return true;
    }

    /**
     * @param userResources     不包含重复元素
     * @param targetUserSources 不包含重复元素
     * @return
     */
    private boolean checkContains(Collection<String> userResources, Collection<String> targetUserSources) {

        if (CollectionUtils.isEmpty(targetUserSources)) {
            return true;
        }

        if (CollectionUtils.isEmpty(userResources)) {
            return false;
        }

        if (userResources.size() < targetUserSources.size()) {
            return false;
        }

        for (String targetUserSource : targetUserSources) {
            if (!userResources.contains(targetUserSource)) {
                return false;
            }
        }

        return true;

    }
}
